module ActiveField

  # 
  # = ActiveField::Core
  # Singleton instance having access to ActionView helpers
  # It manages the rendering of the tags
  #
  class Core
    include Singleton
    
    class << self
      #include ActionView::Helpers::FormHelper # for text_field
      
      # select_date, select_datetime, select_time
      include ActionView::Helpers::DateHelper
      
      # tag(), content_tag()
      include ActionView::Helpers::TagHelper
      
      # check_box_tag, field_set_tag, file_field_tag, form_tag, hidden_field_tag, image_submit_tag,
      # password_field_tag, radio_button_tag, select_tag, submit_tag, text_area_tag, text_field_tag
      include ActionView::Helpers::FormTagHelper
      
      # options_for_select(), ....
      include ActionView::Helpers::FormOptionsHelper
      
      
      # 
      # Create a method for all the fields
      #
      def initialize
        puts 'ActiveField initializing'
      end
      
      # 
      # = build_tag
      #
      # == Usage
      # ActionField::Core.build_tag :text_field, record, field_name, [params...]
      #
      #def build_tag( tag_method, record, field_name, value, *args )
      #  send tag_method, record, field_name, value, *args
      def build_tag( tag_method, *args )
        send tag_method, *args
      end
      
      #
      # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
      # 
      # +underscore+ will also change '::' to '/' to convert namespaces to paths.
      #
      #   "ActiveRecord".underscore         # => "active_record"
      #   "ActiveRecord::Errors".underscore # => active_record/errors
      #
      # Source : vendor/rails/activesupport/lib/active_support/inflector.rb
      #
      # NOTE: the strings passed here we're not extended by ActiveSupport if the model variable
      # was defined in the view. This could allow an easy port to MERB after all...
      #
      def underscore(camel_cased_word)
        camel_cased_word.to_s.gsub(/::/, '/').
          gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
          gsub(/([a-z\d])([A-Z])/,'\1_\2').
          tr("-", "_").downcase
      end
      
      # By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
      # is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
      #
      # +camelize+ will also convert '/' to '::' which is useful for converting paths to namespaces.
      #
      #   "active_record".camelize                # => "ActiveRecord"
      #   "active_record".camelize(:lower)        # => "activeRecord"
      #   "active_record/errors".camelize         # => "ActiveRecord::Errors"
      #   "active_record/errors".camelize(:lower) # => "activeRecord::Errors"
      def camelize(lower_case_and_underscored_word, first_letter_in_uppercase = true)
        if first_letter_in_uppercase
          lower_case_and_underscored_word.to_s.gsub(/\/(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase }
        else
          lower_case_and_underscored_word.first + camelize(lower_case_and_underscored_word)[1..-1]
        end
      end
      
      
      #
      # Similar to +ActionView::Helpers::FormOptionsHelper#options_from_collection_for_select+
      # but returns an array of array instead.
      #
      # Use the return of this method as the +container+ argument to +options_for_select+
      #
      def options_from_collection( collection, value_method, text_method, selected = nil )
        options = collection.map do |element|
          [element.send(text_method), element.send(value_method)]
        end
      end
      
      #
      # Like +radio_button_tag+ but wraps a label tag around it
      # label defaults to the value capitalized
      #
      def radio_tag_with_label( name, value, label = nil, checked = false, options = {} )
        label ||= value.capitalize
        "<label>" + radio_button_tag( name, value, checked, options ) + " " + label + "</label>"
      end
      
      #
      # choices must be like the return of +options_from_collection+
      #
      def radio_group_with_label( name, choices, selected = nil )
        choices.collect do |choice|
          label, value = choice
          checked = (value == selected)
          radio_tag_with_label name, value, label, checked
        end.join
      end
      
    end
    
  end
  
end
